//--------------------------------------------------------------------------------
/*!
\file	Mixer.cpp
\author	bsmith, dkarp
\date	02/21/07
\brief	Mixer Buffer that handles mixing of sound
\par	license
Copyright (c) DigiPen Institute of Technology 2006. All Rights Reserved. 
*/
//--------------------------------------------------------------------------------
#include "stdafx.h"
#include "LowLevel.h"

using namespace sndcore;

//-------------------------------------------------------------------------------
/*!
\brief init mini mixer

\param primaryBuff
primary buffer
\param size
size of buffer

\return error if false
\author	Danny Karp
*/
//-------------------------------------------------------------------------------

bool MiniMixer::Initialize( const SoundBufferDS * primaryBuff, int size )
{
   //create a user defined buffer based of the primary buffer passed in
	SoundBufferOptions ops;
	ops.size_ = size;
	ops.format_ = primaryBuff->GetFormat();

	mixed_ = new SoundBufferUser( );
	
	if( !mixed_->Initialize( ops ) )
		return false;

	return true;
}

//-------------------------------------------------------------------------------
/*!
\brief shutdown mini mixer


\author	Danny Karp
*/
//-------------------------------------------------------------------------------

void MiniMixer::Shutdown()
{
	SAFE_DELETE( mixed_ );
}
//-------------------------------------------------------------------------------
/*!
\brief reset the mixer

\param set_value
 clear value
\author	Danny Karp
*/
//-------------------------------------------------------------------------------
void MiniMixer::Reset( BYTE set_value )
{
	memset( mixed_->DirectRead( NULL ), set_value, mixed_->GetSize() );
}

//-------------------------------------------------------------------------------
/*!
\brief Mix in the data into the mixer

\param mixin 
   channel to mix in
\param size_
  size to mix in 
\param mastaVol
  volume to set


\return error if false
\author	Danny Karp
*/
//-------------------------------------------------------------------------------
#define WORD_RANGE  32768
bool MiniMixer::MixIn( Channel *mixin, DWORD size_, const float &mastaVol  )
{
	DWORD chSize = mixin->GetSound()->GetFormat().wBitsPerSample == 16 ? mixin->GetSound()->GetSize() >> 1 : mixin->GetSound()->GetSize();
	size_ = mixin->GetSound()->GetFormat().wBitsPerSample == 16 ? size_ >> 1 : size_;
	WORD channels = mixin->GetSound()->GetFormat().nChannels;

	 SHORT left_channel = 0, right_channel = 0, tempVal=0;
	 BYTE l_chan = 0, r_chan = 0;

	 short dmax = mixin->GetSound()->GetFormat().wBitsPerSample == 8 ? 255 : WORD_RANGE-1;
	 short dmin = mixin->GetSound()->GetFormat().wBitsPerSample == 8 ? 130 : 1000;
	 short dthresh = (short)(dmax + (dmin-dmax)*mixin->GetCompressionDSPPower());
	
	for( unsigned mixer_buf = 0; mixer_buf < size_ && mixer_buf < chSize; ++mixer_buf )
	{
		int channel_loc = mixer_buf % 2;
		if( mixin->GetSound()->GetFormat().wBitsPerSample == 16 )
		{

			if( channels == 2 && ( mixer_buf % 2 == 0) )
			{
				left_channel=right_channel=0;
				mixin->GetDataFromOffset<SHORT>( 0,0,left_channel );
				mixin->GetDataFromOffset<SHORT>( 1,0,right_channel );
				for (unsigned i=1; i < mixin->GetNumTaps() && mixin->GetDelayDSPPower() > 0; ++i) {
					if (mixin->GetDataFromOffset<SHORT>(0,i,tempVal))
						left_channel = MixSamples(tempVal, left_channel, 1.f,1.f,16);
					if (mixin->GetDataFromOffset<SHORT>(1,i,tempVal))
						right_channel = MixSamples(tempVal, right_channel, 1.f,1.f,16);
				}
				Pan(left_channel,right_channel,mixin->GetPan(),16);
			}

			SHORT *MixerBuff = (SHORT*)mixed_->DirectRead( NULL );

			mixin->MoveCursorsByTemplate<SHORT>(); 
			if (mixin->HasPlayed())
				return true;

			SHORT data_val = ( channel_loc == 1 ) ? right_channel : left_channel;

			MixerBuff[mixer_buf] = 
				MixSamples( data_val,  MixerBuff[mixer_buf], mixin->GetGain(), mastaVol,  mixin->GetSound()->GetFormat().wBitsPerSample );
			
			
			if (mixin->HasCompressionDSP())
				MixerBuff[mixer_buf] = Distortion(MixerBuff[mixer_buf], dthresh, 16);
		}
		else if( mixin->GetSound()->GetFormat().wBitsPerSample == 8 )
		{

			if( channels == 2 && ( mixer_buf % 2 == 0) )
			{
				left_channel=right_channel=128;
				mixin->GetDataFromOffset<BYTE>( 0,0,(BYTE&)left_channel );
				mixin->GetDataFromOffset<BYTE>( 1,0,(BYTE&)right_channel );
				for (unsigned i=1; i < mixin->GetNumTaps() && mixin->GetDelayDSPPower() > 0; ++i) {
					if (mixin->GetDataFromOffset<BYTE>(0,i,(BYTE&)tempVal))
						left_channel = MixSamples(tempVal, left_channel, 1.f,1.f,8);
					if (mixin->GetDataFromOffset<BYTE>(1,i,(BYTE&)tempVal))
						right_channel = MixSamples(tempVal, right_channel, 1.f,1.f,8);
				}
				Pan(left_channel,right_channel,mixin->GetPan(),8);

				l_chan = (BYTE)left_channel;
				r_chan = (BYTE)right_channel;
			}

			BYTE *MixerBuff = (BYTE*)mixed_->DirectRead( NULL );


			mixin->MoveCursorsByTemplate<BYTE>();

			if (mixin->HasPlayed())
				return true;
			

			BYTE byte_val = ( channel_loc == 1 ) ? r_chan : l_chan;

			MixerBuff[mixer_buf] = BYTE(
				MixSamples( short( byte_val ),  short( MixerBuff[mixer_buf] ),
				mixin->GetGain(), mastaVol, mixin->GetSound()->GetFormat().wBitsPerSample ) );

			if (mixin->HasCompressionDSP())
				MixerBuff[mixer_buf] = (BYTE)Distortion(MixerBuff[mixer_buf], dthresh, 8);

		}
		
	}
	return false;
}

